package com.personalink.input.service;

import com.personalink.input.dto.InputProcessResult;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.tika.Tika;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.sound.sampled.*;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.*;

/**
 * 语音处理服务
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class VoiceProcessService {
    
    private final Tika tika = new Tika();
    
    // 支持的音频格式
    private static final Set<String> SUPPORTED_FORMATS = Set.of(
            "audio/mpeg", "audio/mp3", "audio/wav", "audio/x-wav", 
            "audio/mp4", "audio/m4a", "audio/ogg", "audio/webm"
    );
    
    // 最大文件大小 (50MB)
    private static final long MAX_FILE_SIZE = 50 * 1024 * 1024;
    
    // 最大时长 (5分钟)
    private static final long MAX_DURATION_MS = 5 * 60 * 1000;
    
    /**
     * 处理语音输入
     */
    public InputProcessResult processVoice(MultipartFile file, String userId, String sessionId, String language) {
        validateVoiceFile(file);
        
        log.info("开始处理语音，文件名: {}, 大小: {} bytes, 语言: {}", 
                file.getOriginalFilename(), file.getSize(), language);
        
        try {
            // 语音转录
            String transcribedText = transcribeVoice(file, language);
            
            // 语音分析
            InputProcessResult.VoiceAnalysis analysis = analyzeVoice(file, transcribedText);
            
            return InputProcessResult.builder()
                    .userId(userId)
                    .sessionId(sessionId)
                    .inputType("voice")
                    .transcribedText(transcribedText)
                    .voiceAnalysis(analysis)
                    .processedAt(System.currentTimeMillis())
                    .metadata(Map.of(
                            "originalFilename", file.getOriginalFilename(),
                            "fileSize", file.getSize(),
                            "contentType", file.getContentType(),
                            "language", language
                    ))
                    .build();
                    
        } catch (Exception e) {
            log.error("处理语音时发生错误", e);
            throw new RuntimeException("语音处理失败: " + e.getMessage());
        }
    }
    
    /**
     * 验证语音文件
     */
    private void validateVoiceFile(MultipartFile file) {
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("语音文件不能为空");
        }
        
        if (file.getSize() > MAX_FILE_SIZE) {
            throw new IllegalArgumentException("语音文件大小不能超过50MB");
        }
        
        try {
            String mimeType = tika.detect(file.getInputStream());
            if (!SUPPORTED_FORMATS.contains(mimeType)) {
                throw new IllegalArgumentException("不支持的音频格式: " + mimeType);
            }
        } catch (IOException e) {
            throw new IllegalArgumentException("无法检测文件类型");
        }
    }
    
    /**
     * 语音转录
     */
    private String transcribeVoice(MultipartFile file, String language) {
        // 这里应该集成实际的语音识别服务（如OpenAI Whisper、百度语音识别等）
        // 目前返回模拟结果
        
        log.debug("开始语音转录，语言: {}", language);
        
        try {
            // 分析音频基本信息
            AudioInfo audioInfo = analyzeAudioFile(file);
            
            // 模拟转录结果（实际应用中需要调用真实的ASR服务）
            String transcribedText = simulateTranscription(audioInfo, language);
            
            log.debug("语音转录完成，文本长度: {}", transcribedText.length());
            
            return transcribedText;
            
        } catch (Exception e) {
            log.error("语音转录失败", e);
            return "[语音转录失败]";
        }
    }
    
    /**
     * 分析音频文件信息
     */
    private AudioInfo analyzeAudioFile(MultipartFile file) throws IOException, UnsupportedAudioFileException {
        try (ByteArrayInputStream bis = new ByteArrayInputStream(file.getBytes())) {
            // 尝试读取音频文件信息
            try {
                AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(bis);
                AudioFormat format = audioInputStream.getFormat();
                
                long frames = audioInputStream.getFrameLength();
                double durationInSeconds = frames / format.getFrameRate();
                
                return AudioInfo.builder()
                        .sampleRate(format.getSampleRate())
                        .channels(format.getChannels())
                        .sampleSizeInBits(format.getSampleSizeInBits())
                        .durationSeconds(durationInSeconds)
                        .frameLength(frames)
                        .build();
                        
            } catch (UnsupportedAudioFileException e) {
                // 如果无法直接读取，返回估算信息
                log.warn("无法读取音频格式信息，使用估算值");
                return AudioInfo.builder()
                        .sampleRate(44100.0f) // 默认采样率
                        .channels(2) // 默认立体声
                        .sampleSizeInBits(16) // 默认16位
                        .durationSeconds(estimateDuration(file.getSize()))
                        .frameLength(-1)
                        .build();
            }
        }
    }
    
    /**
     * 估算音频时长
     */
    private double estimateDuration(long fileSize) {
        // 粗略估算：假设128kbps的比特率
        double bitrate = 128 * 1000; // 128 kbps
        double fileSizeInBits = fileSize * 8;
        return fileSizeInBits / bitrate;
    }
    
    /**
     * 模拟语音转录
     */
    private String simulateTranscription(AudioInfo audioInfo, String language) {
        // 实际应用中，这里应该调用真实的ASR服务
        // 目前根据音频时长和语言返回模拟文本
        
        double duration = audioInfo.getDurationSeconds();
        
        if (duration < 1) {
            return "你好";
        } else if (duration < 5) {
            return switch (language) {
                case "zh-CN" -> "你好，我想咨询一下相关问题。";
                case "en-US" -> "Hello, I would like to ask about something.";
                case "ja-JP" -> "こんにちは、質問があります。";
                default -> "Hello, I have a question.";
            };
        } else if (duration < 15) {
            return switch (language) {
                case "zh-CN" -> "你好，我最近遇到了一些问题，希望能够得到一些建议和帮助。请问你能帮我分析一下这个情况吗？";
                case "en-US" -> "Hello, I've been having some issues lately and I'm hoping to get some advice and help. Could you help me analyze this situation?";
                case "ja-JP" -> "こんにちは、最近いくつかの問題に直面しており、アドバイスと助けを求めています。この状況を分析していただけませんか？";
                default -> "Hello, I need some help with a situation I'm facing.";
            };
        } else {
            return switch (language) {
                case "zh-CN" -> "你好，我想详细地向你描述一下我最近遇到的情况。这个问题已经困扰我很长时间了，我尝试了很多方法但是都没有得到很好的解决。我希望能够通过与你的交流，找到一个合适的解决方案。你能帮我分析一下这个问题的根本原因，并给出一些实用的建议吗？";
                case "en-US" -> "Hello, I would like to describe in detail the situation I've been facing recently. This problem has been bothering me for a long time, and I've tried many approaches but haven't found a good solution. I hope that through our conversation, I can find an appropriate solution. Could you help me analyze the root cause of this problem and provide some practical advice?";
                case "ja-JP" -> "こんにちは、最近直面している状況について詳しく説明したいと思います。この問題は長い間私を悩ませており、多くの方法を試しましたが、良い解決策を見つけることができませんでした。私たちの会話を通じて、適切な解決策を見つけることができればと思います。この問題の根本原因を分析し、実用的なアドバイスをいただけませんか？";
                default -> "I have a complex situation that I'd like to discuss with you in detail.";
            };
        }
    }
    
    /**
     * 语音分析
     */
    private InputProcessResult.VoiceAnalysis analyzeVoice(MultipartFile file, String transcribedText) {
        try {
            AudioInfo audioInfo = analyzeAudioFile(file);
            
            // 质量评分
            Double qualityScore = calculateVoiceQuality(audioInfo);
            
            // 情感分析（基于转录文本）
            InputProcessResult.SentimentResult emotion = analyzeVoiceEmotion(transcribedText, audioInfo);
            
            // 语音特征分析
            InputProcessResult.VoiceFeatures features = analyzeVoiceFeatures(audioInfo);
            
            // 语言检测
            String detectedLanguage = detectLanguageFromVoice(transcribedText);
            
            // 转录置信度
            Double confidence = calculateTranscriptionConfidence(audioInfo, transcribedText);
            
            return InputProcessResult.VoiceAnalysis.builder()
                    .qualityScore(qualityScore)
                    .emotion(emotion)
                    .features(features)
                    .detectedLanguage(detectedLanguage)
                    .confidence(confidence)
                    .build();
                    
        } catch (Exception e) {
            log.error("语音分析失败", e);
            
            // 返回默认分析结果
            return InputProcessResult.VoiceAnalysis.builder()
                    .qualityScore(0.5)
                    .emotion(InputProcessResult.SentimentResult.builder()
                            .label("neutral")
                            .score(0.5)
                            .emotions(Map.of("neutral", 0.5))
                            .build())
                    .features(InputProcessResult.VoiceFeatures.builder()
                            .pitch(0.5)
                            .tempo(0.5)
                            .volume(0.5)
                            .gender("unknown")
                            .ageRange(30)
                            .build())
                    .detectedLanguage("unknown")
                    .confidence(0.5)
                    .build();
        }
    }
    
    /**
     * 计算语音质量
     */
    private Double calculateVoiceQuality(AudioInfo audioInfo) {
        double score = 0.5; // 基础分
        
        // 采样率评分
        if (audioInfo.getSampleRate() >= 44100) {
            score += 0.2;
        } else if (audioInfo.getSampleRate() >= 22050) {
            score += 0.1;
        }
        
        // 位深度评分
        if (audioInfo.getSampleSizeInBits() >= 16) {
            score += 0.1;
        }
        
        // 时长评分（避免过短或过长）
        double duration = audioInfo.getDurationSeconds();
        if (duration >= 1 && duration <= 300) { // 1秒到5分钟
            score += 0.2;
        } else if (duration > 0.5 && duration < 600) { // 0.5秒到10分钟
            score += 0.1;
        }
        
        return Math.min(score, 1.0);
    }
    
    /**
     * 分析语音情感
     */
    private InputProcessResult.SentimentResult analyzeVoiceEmotion(String transcribedText, AudioInfo audioInfo) {
        // 基于文本内容的情感分析
        Map<String, Double> emotions = new HashMap<>();
        
        String lowerText = transcribedText.toLowerCase();
        
        // 简化的情感关键词检测
        if (lowerText.contains("开心") || lowerText.contains("高兴") || lowerText.contains("happy")) {
            emotions.put("joy", 0.8);
            emotions.put("sadness", 0.1);
            return InputProcessResult.SentimentResult.builder()
                    .label("positive")
                    .score(0.8)
                    .emotions(emotions)
                    .build();
        } else if (lowerText.contains("难过") || lowerText.contains("伤心") || lowerText.contains("sad")) {
            emotions.put("sadness", 0.8);
            emotions.put("joy", 0.1);
            return InputProcessResult.SentimentResult.builder()
                    .label("negative")
                    .score(0.8)
                    .emotions(emotions)
                    .build();
        } else if (lowerText.contains("生气") || lowerText.contains("愤怒") || lowerText.contains("angry")) {
            emotions.put("anger", 0.8);
            emotions.put("joy", 0.1);
            return InputProcessResult.SentimentResult.builder()
                    .label("negative")
                    .score(0.7)
                    .emotions(emotions)
                    .build();
        }
        
        // 默认中性情感
        emotions.put("neutral", 0.6);
        emotions.put("joy", 0.2);
        emotions.put("sadness", 0.1);
        emotions.put("anger", 0.1);
        
        return InputProcessResult.SentimentResult.builder()
                .label("neutral")
                .score(0.5)
                .emotions(emotions)
                .build();
    }
    
    /**
     * 分析语音特征
     */
    private InputProcessResult.VoiceFeatures analyzeVoiceFeatures(AudioInfo audioInfo) {
        // 基于音频信息的特征分析（简化版）
        
        // 根据采样率和时长估算特征
        double duration = audioInfo.getDurationSeconds();
        float sampleRate = audioInfo.getSampleRate();
        
        // 估算音调（基于采样率）
        double pitch = Math.min(sampleRate / 44100.0, 1.0);
        
        // 估算语速（基于时长）
        double tempo = duration > 0 ? Math.min(1.0 / (duration / 10.0), 1.0) : 0.5;
        
        // 估算音量（基于位深度）
        double volume = Math.min(audioInfo.getSampleSizeInBits() / 16.0, 1.0);
        
        // 简化的性别和年龄识别
        String gender = pitch > 0.6 ? "female" : "male";
        int ageRange = (int) (20 + (tempo * 40)); // 20-60岁范围
        
        return InputProcessResult.VoiceFeatures.builder()
                .pitch(pitch)
                .tempo(tempo)
                .volume(volume)
                .gender(gender)
                .ageRange(ageRange)
                .build();
    }
    
    /**
     * 从语音检测语言
     */
    private String detectLanguageFromVoice(String transcribedText) {
        if (transcribedText.matches(".*[\u4e00-\u9fa5]+.*")) {
            return "zh-CN";
        } else if (transcribedText.matches(".*[\u3040-\u309f\u30a0-\u30ff]+.*")) {
            return "ja-JP";
        } else {
            return "en-US";
        }
    }
    
    /**
     * 计算转录置信度
     */
    private Double calculateTranscriptionConfidence(AudioInfo audioInfo, String transcribedText) {
        double confidence = 0.5; // 基础置信度
        
        // 基于音频质量
        if (audioInfo.getSampleRate() >= 44100) {
            confidence += 0.2;
        }
        
        if (audioInfo.getSampleSizeInBits() >= 16) {
            confidence += 0.1;
        }
        
        // 基于转录文本质量
        if (transcribedText.length() > 5 && !transcribedText.contains("[语音转录失败]")) {
            confidence += 0.2;
        }
        
        return Math.min(confidence, 1.0);
    }
    
    /**
     * 音频信息类
     */
    @lombok.Data
    @lombok.Builder
    @lombok.NoArgsConstructor
    @lombok.AllArgsConstructor
    private static class AudioInfo {
        private float sampleRate;
        private int channels;
        private int sampleSizeInBits;
        private double durationSeconds;
        private long frameLength;
    }
}